﻿
namespace PhotoAlbum.Web.Services
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using PhotoAlbum.Web;

    [EnableClientAccess()]
    public class PictureTaggingService : PhotoAlbumService
    {
        [Query(HasSideEffects = false, IsDefault = true, IsComposable = true)]
        public IQueryable<Tag> GetTags()
        {
            return this.ObjectContext.Tags.OrderBy(t => t.Title);
        }

        [Query(HasSideEffects = false, ResultLimit = 20)]
        public IQueryable<Tag> GetPopularTags()
        {
            return this.ObjectContext.Tags.OrderByDescending(t => t.Pictures.Count);
        }

        [Query(HasSideEffects = false, ResultLimit = 20)]
        public IQueryable<Tag> GetTagsForPictureId(int pictureId)
        {
            var picture = this.GetViewablePicture(pictureId);
            return picture.Tags.CreateSourceQuery().OrderBy(t => t.Title);
        }

        [Query(HasSideEffects = false, ResultLimit = 20)]
        public IQueryable<Tag> GetPictureTagsForAlbumId(int albumId)
        {
            var album = this.ObjectContext.Albums.FirstOrDefault(a => a.Id == albumId);
            if(album == null)
            {
                throw new Exception("The album does not exist");
            }
            if (!this.CanUserViewAlbum(album))
            {
                throw new Exception("The album cannot be accessed.");
            }
            return album
                    .Pictures
                    .CreateSourceQuery()
                    .SelectMany(p => p.Tags)
                    .Distinct()
                    .OrderBy(p => p.Title);
        }

        [Query(HasSideEffects = false, ResultLimit = 20)]
        public IQueryable<Tag> GetPictureTagsForUserId(int userId)
        {
            IQueryable<Album> albums;
            if (this.PhotoUser != null
                && this.PhotoUser.Id == userId)
            {
                albums = PhotoUser
                            .Albums
                            .CreateSourceQuery();
            }
            else
            {
                var user = this.ObjectContext.PhotoAlbumUsers.FirstOrDefault(u => u.Id == userId);
                if(user == null)
                {
                    throw new Exception("User with the given ID cannot be found.");
                }
                albums = user.Albums.CreateSourceQuery().Where(a => a.VisibilityStore == (int)AlbumVisibility.Public);
            }
            return albums.SelectMany(a => a.Pictures)
                            .SelectMany(p => p.Tags)
                            .Distinct()
                            .OrderBy(t => t.Title);
        }

        [RequiresAuthentication]
        [Description("Tags a given picture and returns the tag instances that have been retrieved or created for it.")]
        public IQueryable<Tag> TagPictureId(int pictureId, [Required] string comaSeparatedTags)
        {
            var picture = this.GetViewablePicture(pictureId);
            if (picture.Album.OwnerId != this.PhotoUser.Id)
            {
                throw new Exception("Only the owner of the picture can tag it.");
            }
            var result = new List<Tag>();
            picture.Tags.Load();
            foreach (var tagTitle in comaSeparatedTags.Split(',')
                                                 .Select(t => t.Trim())
                                                 .Where(t => !string.IsNullOrEmpty(t)))
            {
                var tag = this.GetOrCreateTagFromTile(tagTitle);
                if(!picture.Tags.Contains(tag))
                {
                    picture.Tags.Add(tag);
                }
                result.Add(tag);
            }
            this.ObjectContext.SaveChanges();
            return result.AsQueryable();
        }

        [Invoke(HasSideEffects = true)]
        public void RemoveTagFromPictureId(int pictureId, int tagId)
        {
            var picture = this.GetViewablePicture(pictureId);
            if (picture.Album.OwnerId != this.PhotoUser.Id)
            {
                throw new Exception("Only the owner of the picture can chnage its tags.");
            }
            picture.Tags.Load();
            var tag = picture.Tags.FirstOrDefault(t => t.Id == tagId);
            if(tag  != null)
            {
                picture.Tags.Remove(tag);
                this.ObjectContext.SaveChanges();
            }
        }

        private static Random random = new Random();

        private Tag GetOrCreateTagFromTile(string tagTitle)
        {
            var result = this.ObjectContext.Tags.FirstOrDefault(t => t.Title.Equals(tagTitle));
            if (result == null)
            {
                var color = System.Drawing.Color.FromKnownColor((System.Drawing.KnownColor)random.Next(29, 163));
                result = new Tag()
                {
                    Title = tagTitle,
                    Color = String.Format("#{0}{1}{2}", color.R.ToString("X"), color.G.ToString("X"), color.B.ToString("X"))
                };
                this.ObjectContext.Tags.AddObject(result);
            }
            return result;
        }
    }
}


